local assets =
{
    -- Asset("ANIM", "anim/panda_fisherman_supply_pack.zip"),
    -- Asset( "IMAGE", "images/inventoryimages/panda_fisherman_supply_pack.tex" ),  -- 背包贴图
    -- Asset( "ATLAS", "images/inventoryimages/panda_fisherman_supply_pack.xml" ),
}
local function GetStringsTable()
    return TUNING.NPC_CHAT_TABLE[ type(TUNING.__NPC_LANGUAGE)=="function" and TUNING.__NPC_LANGUAGE() or TUNING.__NPC_LANGUAGE ] ["npc_item_woodlegs_tent"] or {}
end
-----------------------------------------------------------------------
local function GetItem_Base_prefab_name(item)   ------- 为了兼容带调料的食物，做了特别多的调整
    return item.nameoverride or item.prefab
end

local function GetItemNum(item)
    local num = 1
    if item.components and item.components.stackable then
        num = item.components.stackable.stacksize
    elseif item.replica and item.replica.stackable then
        num = item.replica.stackable:StackSize()
    end
    return num
end

local function PushBackItemGetEvent(inst)
    if inst.replica and inst.replica.npc_base_lib then
        inst.replica.npc_base_lib:PushEvent("item_test_get")
        -- inst:PushEvent("refresh")
    elseif inst.PushEvent then
        inst:PushEvent("item_test_get")    
        -- inst:PushEvent("refresh")
    end
end
local function item_test_fn_all(inst,_item_ask_table, item, slot)
    ---------------------------------------------------------------
    if slot ~= nil then ----- 手动放的时候
        local cmd_table = nil
        for k, temp_cmd_table in pairs(_item_ask_table) do
            if temp_cmd_table.slot == slot then
                cmd_table = temp_cmd_table
                break
            end
        end
        if cmd_table ~= nil then
            if cmd_table.name == GetItem_Base_prefab_name(item) then
                PushBackItemGetEvent(inst)
                return true
            end
        end
        return false
    else    ----------- shift 自动放的时候
        for k, cmd_table in pairs(_item_ask_table) do
            if cmd_table.name == GetItem_Base_prefab_name(item) then
                PushBackItemGetEvent(inst)
                return true
            end
        end
    end
    return false
    ---------------------------------------------------------------
end
local function container_Widget_change(theContainer)

    local function Get_item_ask_table(inst)
        -- print("Get_item_ask_table",inst,inst.components,inst.replica)
        local _item_ask_table = nil
        if inst.components and inst.components.container then
            _item_ask_table = inst.components.container._item_ask_table
        elseif inst.replica and inst.replica.container then
            _item_ask_table = inst.replica.container._item_ask_table            
        end
        return _item_ask_table
    end

    local function widget_update_fn_after(self,inst,doer,...)
        ------------------------------------------------------------------------------
        --- 这里修改背景要求，比如数量要求。
        --- widget 的 children 修改
        ------------------------------------------------------------------------------
        -- inst.container_widget = self
        self._item_ask_table = Get_item_ask_table(inst)
        inst._item_ask_table = self._item_ask_table
        ------------------------------------------------------------------------------        
        local child_fn = {
            ["ItemSlot"] = function(ItemSlot,name,num)
                --------------------------------------------
                if name and num then
                    ItemSlot:ConvertToConstructionSlot(Ingredient(name,num) ,0)
                end
                ItemSlot.base_scale = 1.5
                ItemSlot.highlight_scale = 2.5
                ItemSlot:SetScale(ItemSlot.base_scale)
                --------------------------------------------
            end,
            [GetStringsTable().button_text] = function(button)
                button:SetScale(1.5)
            end,
        }

        if self.children then
            -- 
            for v, child in pairs(self.children) do
                if v and child and child_fn[tostring(child)] then
                    if tostring(child) ~= "ItemSlot" then
                        child_fn[tostring(child)](child)
                    end
                end
            end
            ------ 格子的 table 位置会循环变化，用 self.inv 就能固定了
            for i, cmd_table in ipairs(self._item_ask_table) do
                child_fn["ItemSlot"](self.inv[cmd_table.slot],cmd_table.name,cmd_table.num)
            end
        end
        ------------------------------------------------------------------------------
        self:SetScale(1.2)
        self:MoveToFront()
        ------------------------------------------------------------------------------        
    end

    -----------------------------------------------------------------------------------
    ----- 容器界面名 --- 要独特一点，避免冲突
    local container_widget_name = "npc_item_woodlegs_tent_widget"

    -----------------------------------------------------------------------------------
    local all_container_widgets = require("containers")
    local params = all_container_widgets.params
    if params[container_widget_name] == nil then
                    
                params[container_widget_name] =
                {
                    widget =
                    {
                        slotpos = {},
                        animbank = "ui_construction_4x1",
                        animbuild = "ui_construction_4x1",
                        pos = Vector3(-400, 200, 0),
                        top_align_tip = 50,
                        buttoninfo =
                        {
                            text = GetStringsTable().button_text,
                            position = Vector3(0, -94, 0),
                        },
                        -- ___npc_fn_before = widget_update_fn_before,
                        ___npc_fn_after = widget_update_fn_after,
                    },
                    -- acceptsstacks = false,
                    usespecificslotsforitems = true,
                    type = "cooker",
                    
                }

                for x = -1.5, 1.5, 1 do
                    table.insert(params[container_widget_name].widget.slotpos, Vector3(x * 110, 8, 0))
                end

                params[container_widget_name].itemtestfn = function(theContainer, item, slot)   ----- 这部分也会在server 上执行
                    local _item_ask_table = Get_item_ask_table(theContainer.inst)
                    if _item_ask_table then
                        return item_test_fn_all(theContainer.inst,_item_ask_table, item, slot)
                    else
                        print("_item_ask_table",_item_ask_table)
                    end
                    return false
                end
                
                params[container_widget_name].widget.buttoninfo.fn = function(inst, doer)
                    if inst.components.npc_base_lib then
                        inst:PushEvent("button_click")
                    elseif inst.replica.npc_base_lib then
                        inst.replica.npc_base_lib:PushEvent("button_click")
                    end
                end
                
                params[container_widget_name].widget.buttoninfo.validfn = function(inst)
                    return inst:HasTag("item_ready")
                end
    end
    
    theContainer:WidgetSetup(container_widget_name)

end
local function add_container_before_not_ismastersim_return(inst)
	-------------------------------------------------------------------------------------------------
    ------ 添加背包container组件    --- 必须在 SetPristine 之后，
    -- local container_WidgetSetup = "wobysmall"
    if TheWorld.ismastersim then
        inst:AddComponent("container")
        inst.components.container.openlimit = 1  ---- 限制1个人打开
        -- inst.components.container:WidgetSetup(container_WidgetSetup)
        inst:DoTaskInTime(0.1,function()
            container_Widget_change(inst.components.container)            
        end)

    else
        inst:DoTaskInTime(0.1, function()
            if inst.replica then
                if inst.replica.container then
                --    inst.replica.container:WidgetSetup(container_WidgetSetup)
                    container_Widget_change(inst.replica.container)
                end
            end

        end)
    end
    -------------------------------------------------------------------------------------------------
end
local function Container_Init(inst)
    ----------------------------------------------
        local function SetItemStackNum(item,num)
            if item.components.stackable then
                item.components.stackable.stacksize = num
            end
        end
        local function AskItem(inst)
            local ret = require("prefabs/items/27_woodlegs_tent_event")():AskItem(inst)
            -- print("+++++++++++++++++++++++++++")
            -- for k, v in pairs(ret) do
            --     print(v.slot,v.name,v.num)
            -- end
            -- print("+++++++++++++++++++++++++++")
            return ret
            -- return {
            --     {name = "meatballs" , num = 1 ,slot = 1},
            --     {name = "cutgrass" , num = 3 ,slot = 2},
            --     {name = "goldnugget" , num = 7,slot = 3},
            --     {name = "twigs" ,  num = 4, slot = 4},
            -- }
        end
        local function Refresh_Ask_Items(inst,new_flag)
            local _item_ask_table = inst.npc_everything_data:Get("_item_ask_table") or AskItem(inst)
            if new_flag then
                _item_ask_table = AskItem(inst)
            end
            inst.__net_str:set(json.encode(_item_ask_table))
            inst.components.container._item_ask_table = _item_ask_table
            inst.npc_everything_data:Set("_item_ask_table",_item_ask_table)
        end
        local function CheckItemEnough(inst)
            local crash_flag,ret = pcall(function()
                local container = inst.components.container
                local _item_ask_table = container._item_ask_table
                for i, cmd_table in ipairs(_item_ask_table) do
                    local item = container:GetItemInSlot(cmd_table.slot)
                    if item == nil then
                        return false
                    end
                    if GetItemNum(item) < cmd_table.num then
                        return false
                    end
                end
                return true
            end)

            if crash_flag == false then
                return false
            else
                return ret
            end
        end
        local function refresh_widget(inst)
             ---- 在server 上执行也能刷新给client
            local enough = CheckItemEnough(inst)
            local refresh_flag = false
            if enough == true and not inst:HasTag("item_ready") then
                refresh_flag = true
                inst:AddTag("item_ready")
                inst.npc_base_lib:RPC_AddTags({"item_ready"})
            elseif enough == false and inst:HasTag("item_ready") then
                refresh_flag = true
                inst:RemoveTag("item_ready")
                inst.npc_base_lib:RPC_RemoveTags({"item_ready"})
            end           
            inst:DoTaskInTime(0.1,function()
                if refresh_flag == true then
                    inst:PushEvent("refresh")
                    inst.npc_base_lib:RPC_PushEvent("refresh")
                end
            end)
        end
    ---------------------------------------------------------------   
    inst.components.container.usespecificslotsforitems = true
    inst.components.container.canbeopened = false
    inst:DoTaskInTime(0.1,function() Refresh_Ask_Items(inst) end)   ----- 加载的时候初始化
    inst:ListenForEvent("Refresh_Ask_Items",function() Refresh_Ask_Items(inst,true) end)  --------- 触发列表刷新
    ---------------------------------------------------------------------------
    inst:ListenForEvent("itemget",function(inst,_table)
        if _table and _table.item then

        end
    end)
    inst:ListenForEvent("button_click",function()
        inst.components.container:Close()
    end)
    inst:ListenForEvent("itemget",refresh_widget)
    inst:ListenForEvent("itemlose",refresh_widget)
    ---------------------------------------------------------------
    inst:ListenForEvent("item_test_get",function(_,_table)
        -- print("item_test_get")
        inst:DoTaskInTime(0,function()
            local doer = inst.components.container:GetOpeners()[1]
            if doer == nil then
                doer = inst:GetNearestPlayer(true)
            end
            local _item_ask_table = inst.components.container._item_ask_table
            for k, cmd_table in pairs(_item_ask_table) do
                local item = inst.components.container:GetItemInSlot(cmd_table.slot)
                if item and doer then
                    local has_num = GetItemNum(item)
                    local ask_num = cmd_table.num
                    if has_num > ask_num then
                        local give_back_num = has_num - ask_num
                        doer.npc_base_lib:GiveItemByName(item.prefab,give_back_num)
                        SetItemStackNum(item,ask_num)
                        ---------- 没法刷新了，只能用这个办法刷新按钮
                        inst.components.container:DropItemBySlot(cmd_table.slot)
                        inst.components.container:GiveItem(item,cmd_table.slot)
                    end
                end
            end
            -- refresh_widget(inst)
        end)

    end)
    ---------------------------------------------------------------
    inst:ListenForEvent("onclose",function()
        local ItemEnough = CheckItemEnough(inst)
        inst.npc_everything_data:Set("item_save",true)
        inst.npc_everything_data:Set("slots.num",0)
        local travel_items = {}
        for i = 1, inst.components.container:GetNumSlots(), 1 do    ----- 坑：如果物品不是连续摆放，则会出现 遍历container.slots 为空直接结束循环的问题
            inst.npc_everything_data:Set("slot."..tostring(i),nil)
            local item = inst.components.container:GetItemInSlot(i)
            if item then
                travel_items[GetItem_Base_prefab_name(item)] = GetItemNum(item)
                local code = item:GetSaveRecord()
                inst.npc_everything_data:Set("slot."..tostring(i),code)
                -- print("Remove",item)
                item:Remove()
            end
            inst.npc_everything_data:Set("slots.num",i)
        end

        if ItemEnough == true then
            inst.npc_everything_data:Set("item_save",false)
            inst.npc_everything_data:Set("travel_items",travel_items)
            inst:PushEvent("Travel_Task_Start")
            print("info : Travel_Task_Start")
        else
            print("info ItemEnough false")
        end
    end)
    inst:ListenForEvent("onopen",function()
        if inst.npc_everything_data:Get("item_save") == true then
            local slots_num = inst.npc_everything_data:Get("slots.num") or 0
            for i = 1, slots_num, 1 do
                local code = inst.npc_everything_data:Get("slot."..tostring(i))
                if code then
                    local item = SpawnSaveRecord(code)
                    inst.components.container:GiveItem(item,i)
                end
                inst.npc_everything_data:Set("slot."..tostring(i),nil)
            end
            inst.npc_everything_data:Set("item_save",false)
        end
    end)

end
-----------------------------------------------------------------------
local function Task_Event_Init(inst)
    require("prefabs/items/27_woodlegs_tent_event")():Task_Event_Init(inst)
end
local function Task_Event_Init_Item(inst)
    require("prefabs/items/27_woodlegs_tent_event")():Task_Event_Init_Item(inst)
end
-----------------------------------------------------------------------
local function fn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddMiniMapEntity()
    inst.entity:AddNetwork()
    inst.entity:AddLight()

    inst:SetPhysicsRadiusOverride(.5)
    MakeObstaclePhysics(inst, inst.physicsradiusoverride)

    -- Set Tent icon
    inst.MiniMapEntity:SetIcon("portabletent.png")
    inst.MiniMapEntity:SetPriority(1)

    inst.Light:SetIntensity(.7)
    inst.Light:SetRadius(2)
    inst.Light:SetFalloff(.65)
    inst.Light:SetColour(0 / 255, 245 / 255, 255 / 255)
    inst.Light:Enable(false)

    inst:AddTag("tent")
    inst:AddTag("portabletent")
    inst:AddTag("structure")
    inst:AddTag("npc_item_woodlegs_tent")

    inst.AnimState:SetBank("tent_walter")
    inst.AnimState:SetBuild("tent_walter")
    inst.AnimState:PlayAnimation("idle",true)

    inst.entity:SetPristine()
    inst:ListenForEvent("rpc_remove",inst.Remove)
    ----------------------------------------------------------------------------------------------------------------------------
    inst.__net_str = net_string(inst.GUID, "npc_events_netvars","npc_item_woodlegs_tent") ----- 用json 传送数据同步
    add_container_before_not_ismastersim_return(inst)
    ----------------------------------------------------------------------------------------------------------------------------
    if not TheWorld.ismastersim then
        inst:ListenForEvent("npc_item_woodlegs_tent",function()
            if inst.replica.container then
                inst.replica.container._item_ask_table = json.decode(inst.__net_str:value())
            end
        end)
        return inst
    end

    inst:AddComponent("npc_base_lib")
    inst:AddComponent("npc_everything_data")

    inst:AddComponent("inspectable") --可检查组件
    inst:AddComponent("named")
    inst.components.named:SetName(GetStringsTable().name)
    STRINGS.CHARACTERS.GENERIC.DESCRIBE[string.upper("npc_item_woodlegs_tent")] = GetStringsTable().inspect_str  --人物检查的描述

    ----------------------------------------------------------------------------------------------------------------------------
    inst:AddComponent("portablestructure")  ---- 帐篷收回相关
        inst.components.portablestructure:SetOnDismantleFn(function()
            inst:AddTag("NOCLICK")
            inst.AnimState:PlayAnimation("disassemble")
            inst.SoundEmitter:PlaySound("dontstarve/characters/walter/tent/close")
            inst:ListenForEvent("animover", function()
                if inst.AnimState:AnimDone() and inst.AnimState:IsCurrentAnimation("disassemble") then
                    local DataTable = deepcopy(inst.npc_everything_data.DataTable)
                    local pt = Vector3(inst.Transform:GetWorldPosition())
                    inst.npc_base_lib:RPC_PushEvent("rpc_remove")
                    inst:Remove()
                    -- local item = ReplacePrefab(inst, "npc_item_woodlegs_tent_item")
                    local item = SpawnPrefab("npc_item_woodlegs_tent_item")
                    item.Transform:SetPosition(pt.x, 0, pt.z)
                    item.npc_everything_data.DataTable = DataTable
                    item.AnimState:PlayAnimation("idle_item")

                    item:DoTaskInTime(1,function()
                        if item.Surrounding_Woodlegs and item.Surrounding_Woodlegs:IsValid() and item.npc_base_lib:Distance_Targets(item,item.Surrounding_Woodlegs) > 20 then
                            item.Surrounding_Woodlegs.Transform:SetPosition(pt.x,0,pt.z)
                        end
                    end)

                end
            end)
        end)
    ----------------------------------------------------------------------------------------------------------------------------
    Container_Init(inst)
    Task_Event_Init(inst)
    inst:DoTaskInTime(0,function() --------------------------------------------- 唯一物品
        local tent = TheSim:FindFirstEntityWithTag("npc_item_woodlegs_tent")
        if tent ~= inst then
            tent:Remove()
        end
    end)
    ----------------------------------------------------------------------------------------------------------------------------
    return inst
end
------------------------------------------------------------------------------------------------------------------------------------------------
local function itemfn()
    local inst = CreateEntity()

    inst.entity:AddTransform()
    inst.entity:AddAnimState()
    inst.entity:AddSoundEmitter()
    inst.entity:AddNetwork()

    inst.entity:AddMiniMapEntity()
    inst.MiniMapEntity:SetIcon("portabletent.png")
    inst.MiniMapEntity:SetPriority(1)


    MakeInventoryPhysics(inst)

    inst.AnimState:SetBank("tent_walter")
    inst.AnimState:SetBuild("tent_walter")
    inst.AnimState:PlayAnimation("idle_item")

    inst:AddTag("npc_item_woodlegs_tent")
    inst:AddTag("portableitem") ---- 添加这个tag，放置的时候就不会显示“栽种”了
    inst:AddTag("item")
    inst:AddTag("irreplaceable")
    inst:AddTag("nosteal")

    MakeInventoryFloatable(inst, nil, 0.05, 0.7)

    inst.entity:SetPristine()

    if not TheWorld.ismastersim then
        return inst
    end

    inst:AddComponent("npc_base_lib")
    inst:AddComponent("npc_everything_data")

    inst:AddComponent("inspectable")
    inst:AddComponent("inventoryitem")
    inst.components.inventoryitem:ChangeImageName("portabletent_item")

    inst:AddComponent("named")
    inst.components.named:SetName(GetStringsTable().name)
    STRINGS.CHARACTERS.GENERIC.DESCRIBE[string.upper("npc_item_woodlegs_tent_item")] = GetStringsTable().inspect_str_item  --人物检查的描述

    -----------------------------------------------------------------------------------------------------------------------------------
    inst:AddComponent("deployable")     ------  放置相关配置
        inst.components.deployable.restrictedtag = nil         ---- 不知道为什么，但是必须为nil才能客制化
        inst.components.deployable.mode = DEPLOYMODE.CUSTOM    ---- 放置模式
        inst._custom_candeploy_fn = function(inst, pt, mouseover, deployer, rot)
            if TheWorld.Map:IsOceanAtPoint(pt.x,pt.y,pt.z,true) then
                return false
            end
            if #TheSim:FindEntities(pt.x, 0, pt.z, 10, nil, nil,{"tent","multiplayer_portal"}) > 0 then
                return true
            end
            if inst.npc_base_lib:Is_Point_In_Camp(pt) == false then
                return false
            end
            return true
        end
        inst.components.deployable.ondeploy = function (inst, pt, deployer)
            local tent = SpawnPrefab("npc_item_woodlegs_tent")
            if tent ~= nil then
                tent.Physics:SetCollides(false)
                tent.Physics:Teleport(pt.x, 0, pt.z)
                tent.Physics:SetCollides(true)
        
                tent.AnimState:PlayAnimation("place")
                tent.AnimState:PushAnimation("idle", true)
        
                tent.SoundEmitter:PlaySound("dontstarve/characters/walter/tent/open")
                local DataTable = deepcopy(inst.npc_everything_data.DataTable)
                inst:Remove()
                tent.npc_everything_data.DataTable = DataTable
                PreventCharacterCollisionsWithPlacedObjects(tent)
                tent:DoTaskInTime(0.1,function()
                    tent:PushEvent("Travel_Prepare",true)
                end)
                TheWorld.npc_everything_data:Set("npc_item_woodlegs_tent.item_day",0)   --------- 清除计数
                if inst.Surrounding_Woodlegs and inst.Surrounding_Woodlegs:IsValid() then
                    tent.Surrounding_Woodlegs = inst.Surrounding_Woodlegs

                    if tent.npc_base_lib:Distance_Targets(tent,tent.Surrounding_Woodlegs) > 20 then
                        tent.Surrounding_Woodlegs.Transform:SetPosition(pt.x+1,0,pt.z+1)
                    end
                    
                end
            end
        end
        MakeSmallPropagator(inst)
    -----------------------------------------------------------------------------------------------------------------------------------
    
    Task_Event_Init_Item(inst)
    -----------------------------------------------------------------------------------------------------------------------------------

    inst:DoTaskInTime(0,function()  --------------------------------------------- 唯一物品
        local tent = TheSim:FindFirstEntityWithTag("npc_item_woodlegs_tent")
        if tent ~= inst then
            tent:Remove()
        end
    end)
    -----------------------------------------------------------------------------------------------------------------------------------
    --- 说明书
    inst:ListenForEvent("onpickup",function(inst,_table)
        if _table and _table.owner and _table.owner.npc_base_lib and inst.____Instructions_task == nil then
            _table.owner.npc_base_lib:Wisper(GetStringsTable()["Instructions"])
            inst.____Instructions_task = inst:DoTaskInTime(60,function()
                inst.____Instructions_task = nil
            end)
        end
    end)
    -----------------------------------------------------------------------------------------------------------------------------------

    return inst
end
------------------------------------------------------------------------------------------------------------------------------------------------
return Prefab("npc_item_woodlegs_tent", fn,assets),
        MakePlacer("npc_item_woodlegs_tent_item_placer", "tent_walter", "tent_walter", "idle"),
        Prefab("npc_item_woodlegs_tent_item", itemfn, assets)